<?php

namespace Hilaoyu\SoftetherJsonrpcClient\Api;

use Hilaoyu\SoftetherJsonrpcClient\SoftetherJsonrpcClient;
use Hilaoyu\Utils\UtilArr;


/**
 * Class HubApi
 * @package Hilaoyu\SoftetherJsonrpcClient\Api
 * @property SoftetherJsonrpcClient $softetherJsonrpcClient
 */
class HubApi
{
    protected $client;

    public function __construct(SoftetherJsonrpcClient $softetherJsonrpcClient)
    {
        $this->client = $softetherJsonrpcClient;
    }

    //hub
    public function createHub($hubname, $adminpassword, $online = true, $maxSession = 0)
    {
        return $this->client->request('CreateHub', [
            "HubName_str" => $hubname,
            "AdminPasswordPlainText_str" => $adminpassword,
            "Online_bool" => $online,
            "MaxSession_u32" => $maxSession,
            "NoEnum_bool" => false,
            "HubType_u32" => 0
        ]);
    }

    public function setHub($hubname, $adminpassword, $online = true, $maxSession = 0)
    {
        return $this->client->request('SetHub', [
            "HubName_str" => $hubname,
            "AdminPasswordPlainText_str" => $adminpassword,
            "Online_bool" => $online,
            "MaxSession_u32" => $maxSession,
            "NoEnum_bool" => false,
            "HubType_u32" => 0
        ]);
    }

    public function getHub($hubname)
    {
        return $this->client->request('GetHub', [
            "HubName_str" => $hubname,
        ]);
    }

    public function setHubOnline($hubname, $online = true)
    {
        $status = $this->client->request('SetHubOnline', [
            "HubName_str" => $hubname,
            "Online_bool" => $online,
        ]);

        return $online === UtilArr::get($status, 'Online_bool');
    }

    public function getHubStatus($hubname)
    {
        return $this->client->request('GetHubStatus', [
            "HubName_str" => $hubname,
        ]);
    }

    public function enumHub()
    {
        $hubs = $this->client->request('EnumHub');

        return UtilArr::get($hubs, 'HubList');
    }

    public function deleteHub($hubname)
    {
        $hubname = trim($hubname);
        if (!$hubname) {
            return false;
        }
        return $this->client->request('DeleteHub', ['HubName_str' => $hubname]);
    }

    //nat
    public function enableSecureNAT($hubname,$enable=true)
    {
        $hubname = trim($hubname);
        if (!$hubname) {
            return false;
        }
        $method = $enable ? 'EnableSecureNAT' : 'DisableSecureNAT';
        return $this->client->request($method, ['HubName_str' => $hubname]);
    }
    public function getSecureNATStatus($hubname)
    {
        $hubname = trim($hubname);
        if (!$hubname) {
            return false;
        }
        return $this->client->request('GetSecureNATStatus', ['HubName_str' => $hubname]);
    }
    public function setSecureNATOption($hubname,$useNat=null,$ip=null,$mask=null,$macAddress=null,$useDhcp=null,$dhcpLeaseIPStart=null,$dhcpLeaseIPEnd=null,$dhcpSubnetMask=null,$dhcpGatewayAddress=null,$dhcpDnsServerAddress=null,$dhcpDnsServerAddress2=null,$dhcpPushRoutes='', $natTcpTimeout=null,$natUdpTimeout=null)
    {
        $hubname = trim($hubname);
        if (!$hubname) {
            return null;
        }
        if(! ($options = $this->getSecureNATOption($hubname))){
            return null;
        }

        if(!is_null($useNat)){
            $options['UseNat_bool'] = boolval($useNat);
        }
        if($ip){
            $options['Ip_ip'] = $ip;
        }
        if($mask){
            $options['Mask_ip'] = $mask;
        }
        if($macAddress){
            $options['MacAddress_bin'] = base64_decode(trim($macAddress));
        }


        if(!is_null($useDhcp)){
            $options['UseDhcp_bool'] = boolval($useDhcp);
        }
        if($dhcpLeaseIPStart){
            $options['DhcpLeaseIPStart_ip'] = $dhcpLeaseIPStart;
        }
        if($dhcpLeaseIPEnd){
            $options['DhcpLeaseIPEnd_ip'] = $dhcpLeaseIPEnd;
        }

        if($dhcpSubnetMask){
            $options['DhcpSubnetMask_ip'] = $dhcpSubnetMask;
        }
        if($dhcpGatewayAddress){
            $options['DhcpGatewayAddress_ip'] = $dhcpGatewayAddress;
        }
        if($dhcpDnsServerAddress){
            $options['DhcpDnsServerAddress_ip'] = $dhcpDnsServerAddress;
        }
        if($dhcpDnsServerAddress2){
            $options['DhcpDnsServerAddress2_ip'] = $dhcpDnsServerAddress2;
        }
        if($dhcpPushRoutes){
            $options['DhcpPushRoutes_str'] = $dhcpPushRoutes;
        }
        if($natTcpTimeout){
            $options['NatTcpTimeout_u32'] = $natTcpTimeout;
        }
        if($natUdpTimeout){
            $options['NatUdpTimeout_u32'] = $natUdpTimeout;
        }

        return $this->client->request('SetSecureNATOption', $options);
    }
    public function getSecureNATOption($hubname)
    {
        $hubname = trim($hubname);
        if (!$hubname) {
            return false;
        }
        return $this->client->request('GetSecureNATOption', [
            "RpcHubName_str"=> $hubname,
        ]);
    }
    public function enumNAT($hubname)
    {
        $hubname = trim($hubname);
        if (!$hubname) {
            return false;
        }
        $re = $this->client->request('EnumNAT', [
            "HubName_str"=> $hubname,
        ]);
        return UtilArr::get($re,'NatTable');
    }
    public function enumDHCP($hubname)
    {
        $hubname = trim($hubname);
        if (!$hubname) {
            return false;
        }
        $re = $this->client->request('EnumDHCP', [
            "HubName_str"=> $hubname,
        ]);
        return UtilArr::get($re,'DhcpTable');
    }


    //link
    public function createLink($hubname_ex, $linkname, $host, $port, $account, $password, $hubname = 'DEFAULT',$maxConnection=0)
    {
        $linkname = trim($linkname);

        $re = $this->client->request('CreateLink', [
            "HubName_Ex_str" => $hubname_ex,
            "CheckServerCert_bool" => false,
            "AccountName_utf" => $linkname,
            "Hostname_str" => $host,
            "Port_u32" => $port,
            "ProxyType_u32" => 0,
            "HubName_str" => $hubname,
            "MaxConnection_u32" => $maxConnection,
            "UseEncrypt_bool" => false,
            "UseCompress_bool" => false,
            "HalfConnection_bool" => ($maxConnection > 4),
            "AdditionalConnectionInterval_u32" => 1,
            "ConnectionDisconnectSpan_u32" => 0,
            "AuthType_u32" => 1,
            "Username_str" => $account,
            "HashedPassword_bin" => $this->client::CreateUserPasswordHash($account, $password),
            "PlainPassword_str" => "",
            "ClientX_bin" => "",
            "ClientK_bin" => "",
            "policy:DHCPFilter_bool" => false,
            "policy:DHCPNoServer_bool" => false,
            "policy:DHCPForce_bool" => false,
            "SecPol_CheckMac_bool" => false,
            "SecPol_CheckIP_bool" => false,
            "policy:ArpDhcpOnly_bool" => false,
            "policy:PrivacyFilter_bool" => false,
            "policy:NoServer_bool" => false,
            "policy:NoBroadcastLimiter_bool" => false,
            "policy:MaxMac_u32" => 0,
            "policy:MaxIP_u32" => 0,
            "policy:MaxUpload_u32" => 0,
            "policy:MaxDownload_u32" => 0,
            "policy:RSandRAFilter_bool" => false,
            "SecPol_RAFilter_bool" => false,
            "policy:DHCPv6Filter_bool" => false,
            "policy:DHCPv6NoServer_bool" => false,
            "SecPol_CheckIPv6_bool" => false,
            "policy:NoServerV6_bool" => false,
            "policy:MaxIPv6_u32" => 0,
            "policy:FilterIPv4_bool" => false,
            "policy:FilterIPv6_bool" => false,
            "policy:FilterNonIP_bool" => false,
            "policy:NoIPv6DefaultRouterInRA_bool" => false,
            "policy:VLanId_u32" => 0,
            "policy:Ver3_bool" => false
        ]);

        return $re;
    }

    public function setLinkOnline($hubname, $linkname, $online = true)
    {
        $method = $online ? 'SetLinkOnline' : 'SetLinkOffline';
        $status = $this->client->request($method, [
            "HubName_str" => $hubname,
            "AccountName_utf" => $linkname,
        ]);

        return $status;
    }

    public function enumLink($hubname)
    {
        $result = $this->client->request('EnumLink', [
            "HubName_str" => $hubname,
        ]);

        return UtilArr::get($result, 'LinkList');
    }

    public function getLink($hubname_ex, $linkname)
    {
        $hubname_ex = trim($hubname_ex);
        $linkname = trim($linkname);
        $result = $this->client->request('GetLink', [
            "HubName_Ex_str" => $hubname_ex,
            "AccountName_utf" => $linkname,
        ]);

        return $result;
    }

    public function renameLink($hubname, $linkname, $linkname_new)
    {
        $hubname = trim($hubname);
        $linkname = trim($linkname);
        $linkname_new = trim($linkname_new);
        $result = $this->client->request('RenameLink', [
            "HubName_str" => $hubname,
            "OldAccountName_utf" => $linkname,
            "NewAccountName_utf" => $linkname_new,
        ]);

        return $result;
    }

    public function setLink($hubname_ex, $linkname, $host = null, $port = null, $account = null, $password = null, $hubname = null,$maxConnection=null)
    {
        $hubname_ex = trim($hubname_ex);
        $linkname = trim($linkname);

        if (!($data = $this->getLink($hubname_ex, $linkname))) {
            return null;
        }
        if ($host) {
            $data['Hostname_str'] = $host;
        }
        if ($port) {
            $data['Port_u32'] = $port;
        }
        if ($account) {
            $data['Username_str'] = $account;
        }
        if ($password) {
            $data['HashedPassword_bin'] = $this->client::CreateUserPasswordHash(UtilArr::get($data, 'Username_str'), $password);
        }
        if ($hubname) {
            $data['HubName_str'] = $hubname;
        }
        if ($maxConnection) {
            $data['MaxConnection_u32'] = $maxConnection;
            $data['HalfConnection_bool'] = ($maxConnection > 4);
            //$data['AdditionalConnectionInterval_u32'] = ($maxConnection > 1) ? 1: 0;
        }


        $re = $this->client->request('SetLink', $data);

        return $re;
    }

    public function deleteLink($hubname, $linkname)
    {
        $status = $this->client->request('DeleteLink', [
            "HubName_str" => $hubname,
            "AccountName_utf" => $linkname,
        ]);

        return $status;
    }

    //user
    public function createUser($hubname, $account, $password)
    {
        $hubname = trim($hubname);
        $account = trim($account);

        $re = $this->client->request('CreateUser', [
            "HubName_str" => $hubname,
            "Name_str" => $account,
            "Realname_utf" => $account,
            "Note_utf" => "",
            "ExpireTime_dt" => "",
            "AuthType_u32" => 1,
            "Auth_Password_str" => $password,
            "UserX_bin" => "=",
            "Serial_bin" => "=",
            "CommonName_utf" => "",
            "RadiusUsername_utf" => "",
            "NtUsername_utf" => "",
            "UsePolicy_bool" => false,
            "policy:Access_bool" => false,
            "policy:DHCPFilter_bool" => false,
            "policy:DHCPNoServer_bool" => false,
            "policy:DHCPForce_bool" => false,
            "policy:NoBridge_bool" => false,
            "policy:NoRouting_bool" => false,
            "policy:CheckMac_bool" => false,
            "policy:CheckIP_bool" => false,
            "policy:ArpDhcpOnly_bool" => false,
            "policy:PrivacyFilter_bool" => false,
            "policy:NoServer_bool" => false,
            "policy:NoBroadcastLimiter_bool" => false,
            "policy:MonitorPort_bool" => false,
            "policy:MaxConnection_u32" => 0,
            "policy:TimeOut_u32" => 0,
            "policy:MaxMac_u32" => 0,
            "policy:MaxIP_u32" => 0,
            "policy:MaxUpload_u32" => 0,
            "policy:MaxDownload_u32" => 0,
            "policy:FixPassword_bool" => false,
            "policy:MultiLogins_u32" => 0,
            "policy:NoQoS_bool" => false,
            "policy:RSandRAFilter_bool" => false,
            "policy:RAFilter_bool" => false,
            "policy:DHCPv6Filter_bool" => false,
            "policy:DHCPv6NoServer_bool" => false,
            "policy:NoRoutingV6_bool" => false,
            "policy:CheckIPv6_bool" => false,
            "policy:NoServerV6_bool" => false,
            "policy:MaxIPv6_u32" => 0,
            "policy:NoSavePassword_bool" => false,
            "policy:AutoDisconnect_u32" => 0,
            "policy:FilterIPv4_bool" => false,
            "policy:FilterIPv6_bool" => false,
            "policy:FilterNonIP_bool" => false,
            "policy:NoIPv6DefaultRouterInRA_bool" => false,
            "policy:NoIPv6DefaultRouterInRAWhenIPv6_bool" => false,
            "policy:VLanId_u32" => 0,
            "policy:Ver3_bool" => false
        ]);

        return $re;
    }
    public function getUser($hubname, $account)
    {
        $hubname = trim($hubname);
        $account = trim($account);

        $re = $this->client->request('GetUser', [
            "HubName_str" => $hubname,
            "Name_str" => $account,
        ]);

        return $re;
    }
    public function setUser($hubname, $account, $password=null)
    {
        $hubname = trim($hubname);
        $account = trim($account);
        if( !($options = $this->getUser($hubname,$account))){
            return null;
        }

        if($password){
            $options['Auth_Password_str'] = $password;
        }


        $re = $this->client->request('SetUser', $options);

        return $re;
    }
    public function deleteUser($hubname, $account)
    {
        $hubname = trim($hubname);
        $account = trim($account);

        $re = $this->client->request('DeleteUser', [
            "HubName_str" => $hubname,
            "Name_str" => $account,
        ]);

        return $re;
    }
    public function enumUser($hubname)
    {
        $hubname = trim($hubname);

        $re = $this->client->request('EnumUser', [
            "HubName_str" => $hubname,
        ]);

        return UtilArr::get($re,'UserList');
    }

    public function enumSession($hubname)
    {
        $hubname = trim($hubname);

        $re = $this->client->request('EnumSession', [
            "HubName_str" => $hubname,
        ]);

        return UtilArr::get($re,'SessionList');
    }

    public function deleteSession($hubname,$sessionName)
    {
        $hubname = trim($hubname);

        $re = $this->client->request('DeleteSession', [
            "HubName_str" => $hubname,
            "Name_str" => $sessionName,
        ]);

        return $re;
    }

    public function enumMacTable($hubname)
    {
        $hubname = trim($hubname);

        $re = $this->client->request('EnumMacTable', [
            "HubName_str" => $hubname,
        ]);

        return UtilArr::get($re,'MacTable');
    }


    public function deleteMacTable($hubname,$entity_key)
    {
        $hubname = trim($hubname);

        $re = $this->client->request('DeleteMacTable', [
            "HubName_str" => $hubname,
            "Key_u32" => $entity_key,
        ]);

        return $re;
    }

    public function getError($reArr = true, $clean = true){
        if(!$this->client){
            return $reArr ? [] : '';
        }
        return $this->client->getError($reArr, $clean);
    }

}
